#include "server_spiffs.h"

#define DEFAULT_FD_NUM          5
#define DEFAULT_MOUNT_POINT     "/spiffs"

static const char *TAG_SERVER_SPIFFS = "SPIFFS";

/**
 * @brief       写入文件
 * @param       path:文件路径
 * @param       buffer:文件内容
 * @retval      无
 */
esp_err_t write_spiffs_file(const char* path, const char *content)
{
    char path_name[32] = "/spiffs";
    strcat(path_name, path);

    FILE *file = fopen(path_name, "w");
    if (file == NULL) {
        ESP_LOGE(TAG_SERVER_SPIFFS, "Failed to open file for writing");
        return ESP_FAIL;
    }

    fprintf(file, "%s", content);
    fclose(file);

    return ESP_OK;
}

/**
 * @brief 读取文件内容到buffer
 * 
 * @param path 读取文件的路径
 * @param buffer 读取文件内容到指针&buffer
 * @return esp_err_t
 */
esp_err_t read_spiffs_file(const char* path, char **buffer, size_t *file_len)
{
    /* 检查目标文件是否存在 */
    struct stat st;
    int ret = 0;
    char path_name[32] = "/spiffs";
    strcat(path_name, path);
    ESP_LOGI(TAG_SERVER_SPIFFS, "path_name: %s", path_name);
    ret = stat(path_name, &st);
    if (ret != 0) {
        ESP_LOGI(TAG_SERVER_SPIFFS, "File not exists, errno %d", ret);
        return ESP_FAIL;
    }

    FILE* f = fopen(path_name, "r");
    if (f == NULL) {
        ESP_LOGE(TAG_SERVER_SPIFFS, "Failed to open file for reading");
        return ESP_FAIL;
    }

    // Seek to the end of the file to determine its size
    fseek(f, 0, SEEK_END);
    long file_size = ftell(f);
    fseek(f, 0, SEEK_SET);

    *file_len = file_size;

    // Allocate memory to hold the file content
    *buffer = (char*)calloc(1, file_size + 1);
    if ((*buffer) == NULL) {
        ESP_LOGE(TAG_SERVER_SPIFFS, "Failed to allocate memory for file content");
        fclose(f);
        return ESP_FAIL;
    }

    // 读取1个sizeof(数组大小的字节)
    fread(*buffer, 1, file_size, f);
    (*buffer)[file_size] = '\0'; // Null-terminate the buffer

    fclose(f);
    return ESP_OK;
}

/**
 * @brief       注销spiffs初始化
 * @param       partition_label：分区表标识
 * @retval      无
 */
esp_err_t spiffs_deinit(char *partition_label)
{
    return esp_vfs_spiffs_unregister(partition_label);
}

/**
 * @brief       spiffs初始化
 * @param       partition_label:分区表的分区名称
 * @param       mount_point:文件系统关联的文件路径前缀
 * @param       max_files:可以同时打开的最大文件数
 * @retval      无
 */
esp_err_t spiffs_init(char *partition_label, char *mount_point, size_t max_files)
{
    /* 配置spiffs文件系统各个参数 */
    esp_vfs_spiffs_conf_t conf = {
        .base_path = mount_point,
        .partition_label = partition_label,
        .max_files = max_files,
        .format_if_mount_failed = true,
    };

    /* 使用上面定义的设置来初始化和挂载SPIFFS文件系统 */
    esp_err_t ret_val = esp_vfs_spiffs_register(&conf);

    /* 判断SPIFFS挂载及初始化是否成功 */
    if (ret_val != ESP_OK)
    {
        if (ret_val == ESP_FAIL)
        {
            ESP_LOGI(TAG_SERVER_SPIFFS, "Failed to mount or format filesystem");
        }
        else if (ret_val == ESP_ERR_NOT_FOUND)
        {
            ESP_LOGI(TAG_SERVER_SPIFFS, "Failed to find SPIFFS partition");
        }
        else
        {
            ESP_LOGI(TAG_SERVER_SPIFFS, "Failed to initialize SPIFFS (%s)", esp_err_to_name(ret_val));
        }

        return ESP_FAIL;
    }

    /* 检查SPIFFS文件系统 */
    ret_val = esp_spiffs_check(conf.partition_label);
    if (ret_val != ESP_OK) {
        ESP_LOGI(TAG_SERVER_SPIFFS, "SPIFFS_check() failed (%s)", esp_err_to_name(ret_val));
        return ESP_FAIL;
    } else {
        ESP_LOGI(TAG_SERVER_SPIFFS, "SPIFFS_check() successful");
    }

    /* 打印SPIFFS存储信息 */
    size_t total = 0, used = 0;
    ret_val = esp_spiffs_info(conf.partition_label, &total, &used);
    if (ret_val != ESP_OK)
    {
        ESP_LOGI(TAG_SERVER_SPIFFS, "Failed to get SPIFFS partition information (%s)", esp_err_to_name(ret_val));
    }
    else
    {
        ESP_LOGI(TAG_SERVER_SPIFFS, "Partition size: total: %d, used: %d", total, used);
    }
    // 检查报告的分区大小信息的一致性。
    if (used > total) {
        ESP_LOGI(TAG_SERVER_SPIFFS, "Number of used bytes cannot be larger than total. Performing SPIFFS_check().");
        ret_val = esp_spiffs_check(conf.partition_label);
        // 也可以用于修复损坏的文件、清理未引用的页面等。
        // 更多信息请访问 https://github.com/pellepl/spiffs/wiki/FAQ#powerlosses-contd-when-should-i-run-spiffs_check
        if (ret_val != ESP_OK) {
            ESP_LOGI(TAG_SERVER_SPIFFS, "SPIFFS_check() failed (%s)", esp_err_to_name(ret_val));
            return ESP_FAIL;
        } else {
            ESP_LOGI(TAG_SERVER_SPIFFS, "SPIFFS_check() successful");
        }
    }    

    return ret_val;
}

/**
 * @brief       测试spiffs
 * @param       无
 * @retval      无
 */
void spiffs_test(void)
{
    size_t len = 0;
    /* 检查目标文件是否存在 */
    struct stat st;
    if (stat("/spiffs/test.txt", &st) == 0) { /* 获取文件信息，获取成功返回0 */
        char *buffer = NULL;
        read_spiffs_file("/test.txt", &buffer, &len);
        ESP_LOGI(TAG_SERVER_SPIFFS, "Read from file: %s", buffer);
        if (buffer) {
            free(buffer);
        }
    }

}

void esp_spiffs_module(void)
{
    spiffs_init("storage", DEFAULT_MOUNT_POINT, DEFAULT_FD_NUM);
    // spiffs_test();
    // spiffs_deinit("storage");
}
